开机流程
如下图:
Linux优化
可以通过添加打印module init的log,来check每个module初始化时的时间。从而找到花费时间比较多的module:1
2
3
4
5
6
7
8
9
10
11
12--- a/init/main.c
+++ b/init/main.c
@@ -785,7 +785,7 @@ int __init_or_module
do_one_initcall(initcall_t fn)
if (initcall_blacklisted(fn))
return
-EPERM;
- if (initcall_debug)
+ if (1)
ret =
do_one_initcall_debug(fn);
优化方案:
- 通过一个比gzip更快的方式去解压内核镜像;
- 去掉系统中一些不必要的log打印;
- 去掉一些系统中不需要的驱动模块;
- 启动时即以最大频率(cpu/DDR)且多核一起跑;
Android优化
查看时间:
adb logcat -v threadtime -b events > logcat_envents.txt
adb logcat -v threadtime > logcat.txt
具体到全志H5平台,查看LOG发现:
1 | 01-01 03:00:23.233 1503 1503 I auditd : type=2000 audit(0.0:1): initialized |
用bootchart 图形化显示Android启动过程,如图
定制本地服务
Init程序的log信息位于kernel Log中,通过检索“init starting”,我们可以找到init进程启动了哪些本地服务,如:
1 | [ 5.632951] init: Starting service 'logd-reinit'... |
Init进程解析init.rc及init.xxx.rc之类的文件,启动一些本地服务,如果我们的设备中没有电话模块、蓝牙模块,我们可以将这些没用的本地服务在init.rc里注释掉。笔者做了对比,去掉几个本地服务与没有去掉本地服务,二者在开机时间上几乎没有减少多少,这也可以理解,因为本地服务就是几个程序,少执行和多执行几个程序对于总体开机时间没有多大影响,不过,去掉没有使用的本地服务,对整个系统性能来说,会有微不足道的提升。
优化建议:
- 去掉开机动画服务(service bootanim /system/bin/bootanimation)可以一定程度上提高系统的启动速度。
- 可以通过在execute_one_command函数中统计测量 ,比如大于100ms的命令打印出来,再分析定位原因,这里命令执行时间长基本算BUG。
preloaded classes & resources
全志H5所花费时间:
1 | 01-01 03:00:12.869 1520 1520 I Zygote : Preloading classes... |
Android系统为了提高应用程序的启动速度,会在Zygote进程初始化过程中加载一些常用的java class和资源文件到进程的内存中,从而共享常用的class和resourse资源。
preloaded-classes list(frameworks\base\preloaded-classes
)中预加载的类位于dalvik zygote进程的heap中。在zygote衍生一个新的dalvik进程后,新进程只需加载heap中没有预加载的类(这些后加载进来的类成为该进程所private独有的),这样便加快了应用程序的启动速度。实际上这是一种以空间换时间的办法,因为几乎没有一个应用程序能够使用到所有的预加载类,必定有很多类对于该应用程序来说是冗余的。但是也正如Google所说,智能手机开机远没有启动应用程序频繁——用户开机一次,但直到下次再开机之前可能要运行多个应用程序。因此牺牲一点启动时间来换取应用程序加载时的较快速度是合算的。
preloaded-classes list已经是Google Android工程师使用众多测试工具分析,加以手动微调后形成的最优化预加载列表,涵盖了智能机上最长见的应用类型所需要的各种类。很难想象我们自己能够有什么手段能够获得比这样更优的一个预加载列表。所以,除非你的Android系统是被移植到非智能手机设备上使用(例如MID、EBOOK,可以不需要Telephony相关的类),不建议去“优化”preloaded-classes list。
优化建议:
- preloadClasses()与preloadResources()可以放到两个线程里面跑。
- 修改zygote的nice值,及thread priority。
定制Android系统服务
由Android的启动过程可知,init进程启动了app_process作为zygote,在app_process里启动了Dalvik虚拟机,然后加载执行了第一个Java程序ZygoteInit作为Dalvik主线程,在ZygoteInit里fork了第一个Java程序SystemServer,在SystemServer里启动了大量的Android的核心服务,通常来说这些服务一般不要去动,如果我们的设备里没有使用过某些服务,并且将来也明确不使用,可以将其去掉。
SystemServer启动了哪些Android服务:
1 | PowerManagerService:电源管理服务 |
优化这些services其实就是剔除我们不需要的一些services,而且不仅仅是修改SystemServer.java的问题,任何使用到被优化剔除掉的服务的代码都必须加以修改,否则系统肯定是起不来的。这样工作量大,而且难度也不小,并且有一定风险。因此对这些services的优化要慎之又慎。
PackageManagerService扫描、检查APK安装包信息
PMS对/system/framework,/system/app,/data/app,/data/app-private目录中的APK扫描耗费了大量的时间,如果预置的三方应用很多,这样启动的时间就会越长。
优化建议:
/system/app下的应用,如果是预置应用,在Android.mk建议加上LOCAL_DEX_PREOPT := true控制,在/system/vendor下的预置应用,如果此应用编译时间比较长的,也使用上LOCAL_DEX_PREOPT := true
尽量减少data区内置app的数量,这个会严重影响开机速度,特别是第一次的开机速度。放在system的app 尽量生成odex 这样会加快开机速度。
Readahead
因为IO慢的原因(cpu与存储类设备如emmc通讯),有两段耗时的地方:1. Zygote的preload 资源和class;2. PackageManagerService的包扫描。可以采用Linux上使用较多的readahead机制,大概原理是:
统计开机过程中,读取的块数据信息,记录下来保存;
再次开机,通过记录下来的块数据读取信息,直接起一个服务,预先开始读,zygote或packagemanagerservice要读文件的时候,文件数据已经在cache中了。
这样主要IO时间,跑到readahead进程去了。